package com.caishi.lkx.user.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.caishi.lkx.user.dto.LoginDto;
import com.caishi.lkx.user.ienum.type.UserAccountType;
import com.caishi.lkx.user.ienum.type.UserType;
import com.caishi.lkx.user.login.LoginServiceComposite;
import com.caishi.lkx.user.mapper.ChannelBusinessMapper;
import com.caishi.lkx.user.model.ChannelBusinessModel;
import com.caishi.lkx.user.model.IUserModel;
import com.caishi.lkx.user.model.LoginInfoModel;
import com.caishi.lkx.user.model.UserModel;
import com.caishi.lkx.user.service.IActionRoleService;
import com.caishi.lkx.user.service.IChannelBusinessService;
import com.caishi.lkx.user.service.IUserService;
import com.zzw.common.threadpool.SysThreadPool;
import com.zzw.common.Wrappers;
import com.zzw.common.entity.IBaseMapper;
import com.zzw.common.exception.BizException;
import com.zzw.common.exception.BizRuntimeException;

import com.zzw.common.utils.UUIDUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

@Service("channelBusinessService")
@Slf4j
public class ChannelBusinessServiceImpl implements IChannelBusinessService {
    @Resource
    private ChannelBusinessMapper channelBusinessMapper;

    @Resource
    private UserServiceImpl userService;
    @Resource
    private LoginServiceComposite loginServiceComposite;
    @Resource
    private IActionRoleService actionRoleService;
    @Override
    public IBaseMapper<ChannelBusinessModel, String> getMapper() {
        return channelBusinessMapper;
    }

    @Override
    public IUserService<UserModel> baseService() {
        return userService;
    }

    @Override
    public ChannelBusinessModel register(LoginDto loginDto, HttpServletRequest request, HttpServletResponse response) throws BizException {

        throw new BizException();
    }


    @Override
    public ChannelBusinessModel register(ChannelBusinessModel userModel) {
        if (userModel.getUserType() == null || !UserType.intHaveType(userModel.getUserType(), UserType.channelBusiness)) {
            throw new BizRuntimeException();
        }
        UserModel baseModel = userService.register(userModel.toUserModel());
        return registerCheck(baseModel, userModel.userInfoCopy(baseModel));
    }

    private ChannelBusinessModel registerCheck(UserModel baseUser, ChannelBusinessModel model) {
        if (channelBusinessMapper.contains(baseUser.getId())) {
            String code = model.getCode();
            model.setCode(null);
            this.simpleUpdate(model.clearUserModelMessage());
            model.setCode(code);
            return model.userInfoCopy(baseUser);
        }
        if (StrUtil.isBlank(model.getCode())) {
            // 设置code
            model.setCode(generateCode());
        }
        return this.insert(model.clearUserModelMessage()).userInfoCopy(baseUser);
    }

    private static String generateCode() {
        // 0-25 a-z 26-51 A-Z 52-61 0-9
        int k = 62;
        long uuid = UUIDUtil.generateUUID();
        String str = String.valueOf(uuid);
        int len = str.length();
        int a0 = (int) (uuid % (k - 1) + 1);
        int a1 = Integer.parseInt(str.substring(len - 2, len)) % k;
        int a2 = Integer.parseInt(str.substring(len - 4, len - 2)) % k;
        int a3 = Integer.parseInt(str.substring(len - 6, len - 4)) % k;
        int a4 = Integer.parseInt(str.substring(len - 8, len - 6)) % k;
        int a5 = Integer.parseInt(str.substring(len - 10, len - 8)) % k;
        return String.valueOf(((char) trans(a0))) +
                (char) trans(a1) +
                (char) trans(a2) +
                (char) trans(a3) +
                (char) trans(a4) +
                (char) trans(a5);
    }

    private static int trans(int k) {
        if (k < 26) {
            return k + 97;
        }
        if (k < 52) {
            return k - 26 + 65;
        }
        return k - 52 + 48;
    }

    @Override
    public String code2Name(String code) {
        ChannelBusinessModel model = channelBusinessMapper.selectOne(Wrappers.<ChannelBusinessModel>lambdaQuery().select(ChannelBusinessModel::getId).eq(ChannelBusinessModel::getCode, code));
        if (model == null) return null;
        return selectName(model.getId());
    }

    @Override
    public IPage<ChannelBusinessModel> search(Map<String, Object> param, Page<ChannelBusinessModel> page, boolean total) {
        Future<Long> future = CompletableFuture.supplyAsync(() -> null);
        if (total) {
            future = SysThreadPool.submit(() -> channelBusinessMapper.searchUserCount(param));
        }
        List<ChannelBusinessModel> users = channelBusinessMapper.searchUser(page.offset(), page.getSize(), param,
                page.getOrders().stream().filter(OrderItem::isAsc).map(OrderItem::getColumn).collect(Collectors.toList()),
                page.getOrders().stream().filter(o -> !o.isAsc()).map(OrderItem::getColumn).collect(Collectors.toList())
        );
        try {
            Long count = future.get();
            return page.setRecords(users).setTotal(count == null ? page.getRecords().size() : count);
        } catch (InterruptedException | ExecutionException e) {
            throw new BizRuntimeException(e);
        }
    }

    @Override
    public ChannelBusinessModel addUser(ChannelBusinessModel model, UserAccountType loginType) throws BizException {
        Assert.notEmpty(model.getMobile(), "手机号不能为空");
        Assert.isTrue(model.getUserType() != null && model.getUserType() != 0);
        IUserModel userModel = loginServiceComposite.register(
                LoginInfoModel.builder()
                        .account(model.getMobile())
                        .loginType(loginType)
                        .certificate(model.getPassword())
                        .build(),
                model
        );
        model.setId(userModel.getId());
        if (CollUtil.isNotEmpty(model.getRoleIds())) {
            actionRoleService.userSettingRolesByIds(model.getId(), model.getRoleIds());
        }
        return model;
    }
}
